package productions;

import lexico.SymbolTable;
import exceptions.ParserException;
import lexico.ErrorTable;
import lexico.TokenClass;

/**
 * @author maocleal
 */
public class TermoProduction extends AbstractProductionRule {

    private static TermoProduction instance = new TermoProduction();

    public static TermoProduction getInstance() {
        return instance;
    }


    /**
     * Regra: termo  :  fator (op_mult fator)*;
     * @return
     * @throws ParserException
     */
    @Override
    public boolean analyze(SymbolTable st, ErrorTable et) throws ParserException {
        if (!FatorProduction.getInstance().analyze(st, et)) {
            return false;
        }

        while (OpMultProduction.getInstance().analyze(st, et)) {
            if (!FatorProduction.getInstance().analyze(st, et)) {
                return skipUntilSynchronize(st, et, "Era esperado um fator.");
            }
        }

        return true;
    }

    @Override
    protected void populateFirst() {
        //from fator first
        first.add(TokenClass.OPERATOR_NOT);
        first.add(TokenClass.DELIMITER_OPENING_PARENTHESIS);
        first.add(TokenClass.NUMERIC);
        first.add(TokenClass.NUMERIC_REAL);
        first.add(TokenClass.KEYWORD_VERDADEIRO);
        first.add(TokenClass.KEYWORD_FALSO);
        first.add(TokenClass.IDENTIFIER);
        this.first.add(TokenClass.OPERATOR_PLUS);
        this.first.add(TokenClass.OPERATOR_MINUS);
        first.add(TokenClass.OPERATOR_INCREMENT);
        first.add(TokenClass.OPERATOR_DECREMENT);
        this.first.add(TokenClass.KEYWORD_CAST);
    }

    @Override
    protected void populateFollow() {
        //from exprarit follow
        follow.add(TokenClass.DELIMITER_CLOSING_SQUARE_BRACKET);
        this.follow.add(TokenClass.OPERATOR_LESS);
        this.follow.add(TokenClass.OPERATOR_LESS_EQUAL);
        this.follow.add(TokenClass.OPERATOR_MORE);
        this.follow.add(TokenClass.OPERATOR_MORE_EQUAL);
        this.follow.add(TokenClass.OPERATOR_DIFFERENT);
        this.follow.add(TokenClass.OPERATOR_EQUAL);
        follow.add(TokenClass.OPERATOR_AND);
        follow.add(TokenClass.DELIMITER_COMMA);
        follow.add(TokenClass.DELIMITER_CLOSING_PARENTHESIS);
        follow.add(TokenClass.DELIMITER_SEMICOLON);
        follow.add(TokenClass.DELIMITER_CLOSING_CURLY_BRACKET);
        follow.add(TokenClass.DELIMITER_CLOSING_PARENTHESIS);
        follow.add(TokenClass.DELIMITER_SEMICOLON);
        follow.add(TokenClass.OPERATOR_OR);

        //from opsoma first
        this.follow.add(TokenClass.OPERATOR_PLUS);
        this.follow.add(TokenClass.OPERATOR_MINUS);
    }
}
